/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tbgb;

import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import tbgb.components.twodimesion.BoundComponent;
import tbgb.components.twodimesion.point2dimplements.Point2DFactory;
import tbgb.entity.GameEntity;
import tbgb.log.TBLog;
import tbgb.process.GameProcessManager;

/**
 *
 * @author LưuQuang
 */
public class BaseGame extends GameCanvas implements Runnable
{
    public static final long DEFAULT_LOOP_INTERVAL = 33;
    
    private final Vector processManagers = new Vector();
    private final Vector entities;
    
    private Graphics graphicManager;
    
    private boolean loop = true;
    private boolean paused = false;
    private long loopInterval = DEFAULT_LOOP_INTERVAL;
    
    // misc properties
    private BoundComponent gameBound;
    
    public BaseGame()
    {
        super(true);
        this.entities = new Vector();
        
        setFullScreenMode(true);
    }
    
    public void initialize()
    {
        this.gameBound = Point2DFactory.getInstance().createBoundComponent();
        this.getGameBound().getSizeComponent().width().set(this.getWidth());
        this.getGameBound().getSizeComponent().height().set(this.getHeight());
        
        this.initProcessManagers(processManagers);
    }
    
    protected void initProcessManagers(Vector procManagersContainer)
    {
        
    }

    public void run()
    {
        graphicManager = getGraphics();
        
        while (this.loop)
        {
            long startTime = System.currentTimeMillis();
            
            //update game
            for (int i = 0; i < this.processManagers.size(); ++i)
            {
                GameProcessManager procManager = (GameProcessManager) this.processManagers.elementAt(i);
                procManager.run(this);
            }
            
            this.flushGraphics();
            
            long endTime = System.currentTimeMillis();
            long remainTime = this.loopInterval - (endTime - startTime);
            
            TBLog.logDetail("Start: " + startTime + " End: " + endTime + " Remain: " + remainTime);
            
            if (remainTime > 0)
            {
                try {
                    Thread.sleep(remainTime);
                } catch (InterruptedException ex) {
                }
            }
        }
        
        this.onExit();
    }
    
    protected void onExit()
    {
        System.exit(0);
    }
    
    public void exit()
    {
        this.setLoop(false);
    }

    /**
     * @return the isLoop
     */
    public boolean isLoop() {
        return loop;
    }

    /**
     * @param isLoop the isLoop to set
     */
    public void setLoop(boolean isLoop) {
        this.loop = isLoop;
    }

    /**
     * @return the loopInterval
     */
    public long getLoopInterval() {
        return loopInterval;
    }

    /**
     * @param loopInterval the loopInterval to set
     */
    public void setLoopInterval(long loopInterval) {
        this.loopInterval = loopInterval;
    }

    /**
     * @return the graphicManager
     */
    public Graphics getGraphicManager() {
        return graphicManager;
    }
    
    public boolean addEntity(GameEntity ge)
    {
        boolean isAdded = false;
        for (int i = 0; i < this.processManagers.size(); ++i)
        {
            GameProcessManager procManager = (GameProcessManager) this.processManagers.elementAt(i);
            Object process = ge.getProcess(procManager.getProcessKey());
            if (process != null && procManager.addProcess(process))
            {
                isAdded = true;
            }
        }
        
        if (isAdded)
        {
            this.entities.addElement(ge);
        }
        
        return isAdded;
    }
    
    public void removeEntity(GameEntity ge)
    {
        int entityIndex = this.entities.indexOf(ge);
        if (entityIndex >= 0)
        {
            this.removeEntityAt(entityIndex);
        }
    }
    
    public void removeEntityAt(int index)
    {
        GameEntity ge = (GameEntity) this.entities.elementAt(index);
        
        for (int i = 0; i < this.processManagers.size(); ++i)
        {
            GameProcessManager procManager = (GameProcessManager) this.processManagers.elementAt(i);
            Object process = ge.getProcess(procManager.getProcessKey());
            if (process != null)
            {
                procManager.removeProcess(process);
            }
        }
        
        this.entities.removeElementAt(index);
    }
    
    public void clearGraphic(int color)
    {    
        graphicManager.setColor(color);
        graphicManager.fillRect(0, 0, getWidth(), getHeight());
    }
    
    public void pause()
    {
        this.paused = true;
    }
    
    public void resume()
    {
        this.paused = false;
    }

    /**
     * @return the gameBound
     */
    public BoundComponent getGameBound() {
        return gameBound;
    }

    /**
     * @return the paused
     */
    public boolean isPaused() {
        return paused;
    }
}
